/******************************************************************************
 *                                                                            *
 *                            Volatile Programming                            *
 *                                   Menu.h                                   *
 *                                                                            *
 ******************************************************************************
 *                                                                            *
 * By: Volatile Pulse                                                         *
 * What: Menu Class                                                           *
 * Date: 06.15.2012                                                           *
 *                                                                            *
 ******************************************************************************
 * Use:                                                                       *
 *    // Define Empty Menu with defaults                                      *
 *      // No Title                                                           *
 *      // No Selectors                                                       *
 *      // Menu in the Top Left Corner                                        *
 *    Menu MenuExample                                                        *
 *                                                                            *
 *    // Define Menu with Title FooBar and .. Left and Right Selectors        *
 *    // and a location of the Bottom Right Corner                            *
 *    Menu MenuExample("FooBar", "..", "..", BOTTOM, RIGHT)                   *
 *                                                                            *
 *    // Set Title as "MenuExample Title"                                     *
 *    MenuExample.SetTitle("MenuExample Title")                               *
 *                                                                            *
 *    // Set Left Selector to == and Right Selector to !!                     *
 *    MenuExample.SetSelectors("==", "!!")                                    *
 *                                                                            *
 *    // Set vertical location to center, and horizontal location to center   *
 *    MenuExample.SetLocation(CENTER, CENTER)                                 *
 *                                                                            *
 *    // Set Wrap Around Option (Default is true)                             *
 *    MenuExample.Wrap(false)                                                 *
 *                                                                            *
 *    // Add Option My Option to the end of the menu                          *
 *    MenuExample.AddOption("My Option")                                      *
 *                                                                            *
 *    // Set Option number 1 to Hello World                                   *
 *    MenuExample.SetOption(1, "Hello World")                                 *
 *                                                                            *
 *    // Returns the user's last selection                                    *
 *    MenuExample.LastSelection()                                             *
 *                                                                            *
 *    // Returns the size of the menu from how many options are in it         *
 *    MenuExample.Size()                                                      *
 *                                                                            *
 *    // Display MenuExample with Option 2 Selected and Return user selection *
 *    // Use the arrow keys on the keyboard and enter to navigate the menu    *
 *    MenuExample.Play(2)                                                     *
 *                                                                            *
 ******************************************************************************/
// TODO (Volatile Pulse#9#): Allow Options with a value, On/Off, 1-10, any strings.
// TODO (Volatile Pulse#9#): Allow multiple colors within each option.

#ifndef _VP_MENU_H_
#define _VP_MENU_H_

#ifdef _WIN32

#include <iostream>
#include <vector>
#include <string>

#include "header.h"

// Define Menu Positions
enum position{LEFT, CENTER, RIGHT, TOP, BOTTOM};

class Menu {
public:
    // Define Empty Menu with a Title and set Left and Right Selectors
    Menu (std::string title = "",
          std::string leftSelector = "",
          std::string rightSelector = "",
          position verticalPosition = TOP,
          position horizontalPosition = LEFT) {
        SetTitle(title);
        SetSelectors(leftSelector, rightSelector);
        SetLocation(verticalPosition, horizontalPosition);
        Wrap(true);
        iLastSelection = 1;
    }

    // Set Title for the Menu
    void SetTitle(std::string title = "") {
        strMenuTitle = title;
    }

    // Set Left and Right Selectors
    void SetSelectors(std::string leftSelector = "", std::string rightSelector = "") {
        strLeftSelector = leftSelector;
        strRightSelector = rightSelector;
    }

    // Set Menu Location
    void SetLocation(position verticalPosition = TOP, position horizontalPosition = LEFT) {
        posVPosition = verticalPosition;
        posHPosition = horizontalPosition;
    }

    // Allow Option Selection to return from bottom/top to top/bottom
    void Wrap(bool wrapAround = true) {
        bWrapAround = wrapAround;
    }

    // Add new Option
    void AddOption(std::string option = "") {
        vMenuOptions.push_back(option);
    }

    // Set Option x to "text"
    void SetOption(unsigned int number = 1, std::string option = "");

    // Allow Option Selection to return from bottom/top to top/bottom
    int LastSelection() {
        return iLastSelection;
    }

    // Allow Option Selection to return from bottom/top to top/bottom
    int Size() {
        return vMenuOptions.size();
    }

    // Display menu with an option already highlighted
    int Play(int startPosition = 1);
private:
    // Define a string to hold the left selector
    std::string strMenuTitle;
    // Define a string to hold the left selector
    std::string strLeftSelector;
    // Define a string to hold the right selector
    std::string strRightSelector;
    // Define a position to hold the vertical position
    position posVPosition;
    // Define a position to hold the horizontal position
    position posHPosition;
    // Define a vactor for storing the option strings
    std::vector<std::string> vMenuOptions;
    // Define an int to hold the last selected option
    int iLastSelection;
    // Define wrap around option
    bool bWrapAround;
};

void Menu::SetOption(unsigned int number, std::string option) {
    // Resize vMenuOptions to allow option at position
    if(vMenuOptions.size() < number)
        vMenuOptions.resize(number, "");

    // Assign the new option
    vMenuOptions[(number - 1)] = option;
}

int Menu::Play(int startPosition) {
    // Clear the screen
    VP_ClearScreen();

    // Draw Title
    if(!strMenuTitle.empty()) {

        // Print Title
        VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - strMenuTitle.length()) :
                   (posHPosition == CENTER) ? ((79 - strMenuTitle.length())/2) :
                   /*(posHPosition == LEFT) ?*/ strLeftSelector.length()),
                  ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                   (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                   /*(posVPosition == TOP) ?*/ 0));
        std::cout << strMenuTitle;

        // Print Seperator
        VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - strMenuTitle.length()) :
                   (posHPosition == CENTER) ? ((79 - strMenuTitle.length())/2) :
                   /*(posHPosition == LEFT) ?*/ strLeftSelector.length()),
                  ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                   (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                   /*(posVPosition == TOP) ?*/ 0) + 1);
        for(unsigned int i = 0; i < strMenuTitle.length(); i ++)
            std::cout << "-";
    }

    // Draw Options
    for(unsigned int i = 0; i < vMenuOptions.size(); i ++) {
        // Output Menu Option
        VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - vMenuOptions[i].length()) :
                   (posHPosition == CENTER) ? ((79 - vMenuOptions[i].length())/2) :
                   /*(posHPosition == LEFT) ?*/ strLeftSelector.length()),
                  ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                   (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                   /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? i : (i + 2)));
        std::cout << vMenuOptions[i];
    }
    // Define Variables
    unsigned int iChoice = startPosition;
    int iKeyPress;

    // Handle User Input until ENTER is Pressed
    do {
        // Draw Left Selector
        VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - vMenuOptions[(iChoice - 1)].length() - strLeftSelector.length()) :
                   (posHPosition == CENTER) ? ((79 - vMenuOptions[(iChoice - 1)].length())/2 - strLeftSelector.length()) :
                   /*(posHPosition == LEFT) ?*/ 0),
                  ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                   (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                   /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
        std::cout << strLeftSelector;

        // Draw Right Selector
        VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length()) :
                   (posHPosition == CENTER) ? ((79 + vMenuOptions[(iChoice - 1)].length())/2) :
                   /*(posHPosition == LEFT) ?*/ strLeftSelector.length() + vMenuOptions[(iChoice - 1)].length()),
                  ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                   (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                   /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
        std::cout << strRightSelector;

        iKeyPress = VP_GetCh();

        // Handle User Input
        switch (iKeyPress) {
            // User Pressed Up
        case VK_UP:
            // Clear Left Selector
            VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - vMenuOptions[(iChoice - 1)].length() - strLeftSelector.length()) :
                       (posHPosition == CENTER) ? ((79 - vMenuOptions[(iChoice - 1)].length())/2 - strLeftSelector.length()) :
                       /*(posHPosition == LEFT) ?*/ 0),
                      ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                       (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                       /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
            for(unsigned int i = 0; i < strLeftSelector.length(); i ++)
                std::cout << " ";

            // Clear Right Selector
            VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length()) :
                       (posHPosition == CENTER) ? ((79 + vMenuOptions[(iChoice - 1)].length())/2) :
                       /*(posHPosition == LEFT) ?*/ strLeftSelector.length() + vMenuOptions[(iChoice - 1)].length()),
                      ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                       (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                       /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
            for(unsigned int i = 0; i < strRightSelector.length(); i ++)
                std::cout << " ";

            // Set iChoice and allow for loop around
            iChoice = ((iChoice == 1) ? ((bWrapAround) ? vMenuOptions.size() : 1) : (iChoice - 1));
            break;

            // User Pressed Down
        case VK_DOWN:
            // Clear Left Selector
            VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length() - vMenuOptions[(iChoice - 1)].length() - strLeftSelector.length()) :
                       (posHPosition == CENTER) ? ((79 - vMenuOptions[(iChoice - 1)].length())/2 - strLeftSelector.length()) :
                       /*(posHPosition == LEFT) ?*/ 0),
                      ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                       (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                       /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
            for(unsigned int i = 0; i < strLeftSelector.length(); i ++)
                std::cout << " ";

            // Clear Right Selector
            VP_GoToXY(((posHPosition == RIGHT) ? (79 - strRightSelector.length()) :
                       (posHPosition == CENTER) ? ((79 + vMenuOptions[(iChoice - 1)].length())/2) :
                       /*(posHPosition == LEFT) ?*/ strLeftSelector.length() + vMenuOptions[(iChoice - 1)].length()),
                      ((posVPosition == BOTTOM) ? (25 - Size() - 2) :
                       (posVPosition == CENTER) ? ((25 - Size() - 2)/2) :
                       /*(posVPosition == TOP) ?*/ 0) + ((strMenuTitle.empty()) ? (iChoice - 1) : (iChoice + 1)));
            for(unsigned int i = 0; i < strRightSelector.length(); i ++)
                std::cout << " ";

            // Set iChoice and allow for loop around
            iChoice = ((iChoice == vMenuOptions.size()) ? ((bWrapAround) ? 1 : vMenuOptions.size()) :(iChoice + 1));
            break;
            // User Pressed Enter
        }
    } while (iKeyPress != VK_RETURN);

    // Set iLastSelection to iChoice
    iLastSelection = static_cast<int>(iChoice);

    // Return Users Selection
    return iLastSelection;
}

#endif

#endif